// arcade controller thing // Copyright (c) 2017 Clinton Ebadi // GPLv3 or (at your option) any later version // .. insert license text here ... // todo: // - hinge // - screw holes + captive nut to mount // - internal mount for mcu and battery // - hole for usb panel mount // - bevel lid // maybe/wishlist: // - wire routing clips on panel? // - buttons on side for pinball? // - vent under mcu/battery? // - slant panel toward player? // bugs: // - hinge is not aligned -- either male arm length or connector placement is wrong use use use use // PREVIEW preview(); module preview () { rotate ([-10, 0, 0]) translate ([0, 0, box_depth+20]) panel (); case (); for (i = [2 ,4]) translate ([panel_width+hinge_joint_width*i, 0, 0]) hinge_male (); } // CONFIGURATION panel_width = 250; panel_height = 130; panel_bevel = 2; // fixme: calculate based on box_base_thickness? box_depth = 80; box_wall = 2; box_base_thickness = 5; $button_d = 30; // I think this should be special joystick_width = 85; joystick_height = 40; hinge_arm_width = 6; hinge_arm_thickness = 6; hinge_arm_length = 50; // size of block to cut female connector from hinge_base_size = [hinge_arm_width * 2, hinge_arm_thickness * 2, hinge_arm_thickness * 2]; hinge_x_offset = 15; // distance from side of case // gunk that should be elsewhere... // bcube parameters, clean up cr = box_wall*2; cres = 0; // switch to hide panel in previews _hide_panel = false; // PANEL COMPONENTS module button (bezel = $button_d+4) { circle (d=$button_d); %circle(d=bezel); } module joystick () { bolt_d = 8; center_hole_d = 24; for (x = [-joystick_width/2, joystick_width/2], y = [-joystick_height/2, joystick_height/2]) { translate ([x, y, 0]) circle (d=bolt_d); // need slot instead } circle (d=center_hole_d); %square ([joystick_width, joystick_height], center=true); // not right... } // CASE module case_base (width=panel_width, height=panel_height, d=box_base_thickness) { bcube([width, height, d], cr, cres); } module case_walls () { difference () { union () { difference() { bcube([panel_width, panel_height, box_depth-box_base_thickness], cr, cres); bcube([panel_width-box_wall*2, panel_height-box_wall*2, box_depth+1], cr, cres); // FIXME: does this accidentally cut some of the bottom out? } attach (case_connector_wall ([panel_width/2-hinge_x_offset, -box_wall+0.01, box_depth/2]), hinge_connector_back (h=hinge_base_size[2]+(hinge_arm_thickness+panel_bevel)/2)) hinge_female_base (support=true); attach (case_connector_wall ([-panel_width/2+hinge_x_offset, -box_wall+0.01, box_depth/2]), hinge_connector_back (h=hinge_base_size[2]+(hinge_arm_thickness+panel_bevel)/2)) hinge_female_base (support=true); } attach (case_connector_wall ([panel_width/2-hinge_x_offset, -box_wall+0.01, box_depth/2]), hinge_connector_back (h=hinge_base_size[2]+(hinge_arm_thickness+panel_bevel)/2)) hinge_female_cut (); attach (case_connector_wall ([-panel_width/2+hinge_x_offset, -box_wall+0.01, box_depth/2]), hinge_connector_back (h=hinge_base_size[2]+(hinge_arm_thickness+panel_bevel)/2)) hinge_female_cut (); } %connector (case_connector_wall ([panel_width/2-hinge_x_offset, -box_wall+0.01, box_depth/2])); } module case () { case_base (); translate ([0, 0, box_depth/2]) case_walls (); } // todo: // specify which wall (rear, front, left, right). vector addition may help... // offset from center of wall, as vector (and use vector subtraction!) // optional: inside/outside CASE_WALL_BACK = [0, panel_height/2, -box_base_thickness/2]; function case_connector_wall (offset=[0,0,0], wall=CASE_WALL_BACK) = [ wall + offset, [0, -1, 0], 0 ]; // HINGE // hinge todo: // allow override of global base dimensions // maybe: add connector for pin to socket so that can easily be test // fit in software for a nicer preview function hinge_connector_back (th=hinge_arm_thickness*2, h=hinge_base_size[2]) = [ [0, th/2, h/2], [0,1, 0], 0 ]; function hinge_connector_bottom (th=hinge_arm_thickness*2, h=hinge_base_size[2]) = [ [0, 0, -h/2], [0, 0, 1], 0 ]; // todo: // gusset support underneath (with argument to toggle) module hinge_female_base (support=false) { // %connector (hinge_connector_back ()); // %connector (hinge_connector_bottom ()); color ([0.5,0.3,0.1, 0.3]) cube (hinge_base_size, center=true); if (support) { corner = [ [ 0, hinge_base_size[1]/2, -hinge_base_size[2]/2], [ 0, -1, -1 ], 0]; base_a = [ [0, hinge_base_size[1]/2, -hinge_base_size[2]/2], [1, 0, 0], 0]; connector (corner); connector (base_a); // fixme: calculate actual radius color ([0.5,0.7,0.1, 0.3]) bconcave_corner_attach(base_a, corner , l=hinge_base_size[1], cr=hinge_base_size[0],cres=0, ext_corner=false, th=0); } } module hinge_female_cut () { joint_male_negative (male_joint_width=hinge_arm_width, male_joint_thickness=hinge_arm_thickness, forward_rom=90, backward_rom=90, male_joint_height=hinge_arm_length); } module hinge_female (support=false) { difference () { hinge_female_base (support); hinge_female_cut (); } } module hinge_male () { for (i=[0,1]) mirror ([0, i, 0]) translate ([0, -hinge_arm_length/4, 0]) joint_male (male_joint_width=hinge_arm_width, male_joint_thickness=hinge_arm_thickness, male_joint_height=hinge_arm_length/2, side=true); } // PANEL // fixme: when attachment axis is [0, 0, -1] something makes the math // go funky and the connector is facing upward, adding very slight y // misalignment "fixes" it... PANEL_BOTTOM = [ [ 0, 0, -box_base_thickness/2+0.01 ], [ 0, 0.000000000001, -1 ] ]; PANEL_TOP = [ [ 0, 0, box_base_thickness/2-0.01 ], [ 0, 0, 1 ] ]; function panel_connector (offset=[0,0,0], wall=PANEL_BOTTOM) = [ wall[0]+offset, wall[1], 0 ]; module panel () { difference () { union () { // bevel translate ([0, 0, panel_bevel/2]) { case_base (d=box_base_thickness-panel_bevel); } case_base (width=panel_width-box_wall*2-0.1, height=panel_height-box_wall*2-0.1); } if (!_hide_panel) { linear_extrude (box_base_thickness*2,center=true) panel_layout (); } } attach (panel_connector (offset=[panel_width/2-hinge_x_offset, panel_height/2-hinge_arm_length, 0]), hinge_connector_bottom ()) hinge_female (); attach (panel_connector (offset=[-panel_width/2+hinge_x_offset, panel_height/2-hinge_arm_length, 0]), hinge_connector_bottom ()) hinge_female (); } module panel_attach (position, angle=0) { x = position[0]; y = position[1]; c1 = [ [x, y, box_base_thickness/2], [0,0,1], angle ]; a1 = [ [0,0, 0], [0,0,0], 0 ]; // %connector (c1); // fixme: don't use 2d for layout attach (c1, a1) children (); } // panel layout inspired by the Neo Geo layout module panel_layout () { translate ([-panel_width/2 + 40, 0, 0]) { panel_attach ([0, 0], 90) joystick (); // p1, coin (floating off in the distance...) translate ([140, 0, 0]) { $button_d=16; for (x = [0, $button_d+10]) { panel_attach ([x, 42]) button (); } } // a, b, c, d translate ([60, -20, 0]) { panel_attach ([0, 0]) button (); for (i = [ 1 : 3 ]) { panel_attach ([i*($button_d+10)-10, $button_d]) button (); } } } }